-- SkyRelicFunctionM
-- created by panyl
-- 空战探索模块

module("SkyRelicFunctionM", package.seeall);

local MEDAL_GROUP_ID = 36;
local RELIC_SCRAP_ID = 10000;

local functionTable = {};
local ruleToId = {};
local rules = {};
local remindTable = {};
local medalTable = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    functionTable = {};
    ruleToId = {};
    medalTable = {};

    -- 转换下relic_function_CSV信息表
    local relic_function_CSV = get_relic_function_CSV();
    for i = 1, #relic_function_CSV do
        local row = relic_function_CSV[i];
        functionTable[row.id] = row;

        ruleToId[row.rule] = ruleToId[row.rule] or {};

        table.insert(ruleToId[row.rule], row.id);

        if row.rule == "sky_medal" then
            medalTable[row.medal_id] = row.id;
        end
    end
end

-- 模块初始化操作
function init()
    remindTable = {};
    if not _init then
        loadCsv();

        -- 载入所有的规则处理子模块
        rules = LOAD_PATH("game/logic/module/sky_relic_functions");
    end

    EventMgr.removeAll("SkyRelicFunctionM");
    -- 关注奖励事件
    EventMgr.register("SkyRelicFunctionM", event.DO_BONUS, whenDoBonus);
    EventMgr.register("SkyRelicFunctionM", event.ITEM_COUNT_UPDATED, whenItemUpdate);
end

-- 开启勋章功能
function openMedalFunction(classId)
    local id = medalTable[classId];

    if id == nil then
        return;
    end

    -- 如果是勋章奖励的话，检查对应的勋章是否开启
    if isOpenMedalFunction(classId) then
        return;
    end

    develop(medalTable[classId], true);

    -- 迷宫外开启直接设置勋章数量为0
    local count = ItemM.getAmount(ME.user, classId);

    if DungeonM.isPause() or not DungeonM.isInDungeon() then
        -- 数量大于0才清除
        if count > 0 then
            ItemM.updateItem(ME.user, classId, 0);
        end
    end
end

-- （开启勋章功能）永恒之塔只在服务端奖励，需要关注下服务端发下的来的消息
function whenItemUpdate(classId)
    if ItemM.query(classId, "group") == MEDAL_GROUP_ID then
        -- 如果是勋章奖励的话，检查对应的勋章是否开启
        openMedalFunction(classId);
    end
end

-- 关注奖励事件
function whenDoBonus(para)

    local classId = para[2];

    if ItemM.query(classId, "group") == MEDAL_GROUP_ID then
        openMedalFunction(classId);
    else
        -- 掠夺许可证相关
        local cond = query(4, "condition");
        local scrapId = SkyResourceM.queryByAlias("relic_scrap", "class_id");
        local needAmount = cond["relic_scrap"];

        if classId ~= scrapId then
            -- 不是要统计的东西
            return;
        end

        if ME.user.dbase:query("rob_permit_show", 0) == 1 then
            -- 已经允许显示了
            return;
        end

        -- 当前的数量是否已经超过指定数量
        local nowAmount = ItemM.getAmount(ME.user, scrapId);
        if nowAmount >= needAmount then
            ME.user.dbase:set("rob_permit_show", 1);
        end
    end
end

function query(id, path)
    local m = functionTable[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 根据PageNo获取所有的项目
function getItemListByPageNo(pageNo, type)
    local finalList = {};
    for _, info in pairs(functionTable) do
        if query(info.id, "page") == pageNo and
            query(info.id, "type") == type then

            if info.rule == "sky_medal" then
                if getLevel(info.id) > 0 then
                    table.insert(finalList, info);
                end
            else
                table.insert(finalList, info);
            end
        end
    end
    return finalList;
end

-- 根据规则获取id
function getIdsByRule(rule)
    local arr = ruleToId[rule] or {};
    if #arr == 1 then
        return arr[1];
    end

    return arr;
end

-- 所有的属性
function getAllProps(user)
    local funcMap = user.dbase:query("relic_function", {});

    local props = {};

    for id, _ in pairs(funcMap) do
        local techInfo = query(id, "tech");

        if type(techInfo) == "table" then
            if techInfo["prop"] then
                props = table.append(props, table.deepcopy(techInfo["prop"]));
            end
        elseif type(techInfo) == "string" then
            -- 配置了公式
            local formuaName = techInfo;
            local level = getLevel(id);
            props =  table.append(props, FormulaM.invoke(formuaName, level));
        end
    end

    return props;
end

-- 功能等级
function getLevel(id)
    local funcMap = ME.user.dbase:query("relic_function", {});

    return funcMap[id] or 0;
end

-- 计算消耗
function calcCost(id)
    -- 如果配置的就是table
    local cost = query(id, "cost");
    if type(cost) == "table" then
        return cost;
    end

    local formula;
    if type(cost) == "string" and string.startWith(cost, "formula_") then
        formula = string.sub(cost, string.len("formula_") + 1);
        cost = FormulaM.invoke(formula, id);
    end

    if type(cost) ~= "table" then
        return {};
    end

    return cost;
end

-- 是否显示泡泡
function needShowBubble(id, level)
    if not checkPreCondition(id)
        and getLevel(id) <= 0 then
        -- 不满足显示条件
        return false;
    end
    return canDevelop(id) == true and not isStrengthenItemReminded(id, level);
end

-- 某一标签页下的是否有需要显示泡泡的
function needShowBubbleForIndex(pageNo, type)
    local list = getItemListByPageNo(pageNo, type);
    for _, info in pairs(list) do
        local level = SkyRelicFunctionM.getLevel(info.id);
        if needShowBubble(info.id, level) then
            return true;
        end
    end
    return false;
end

-- 获取强化项是否已经提醒过
function isStrengthenItemReminded(id, level)
    -- 获取当前的提醒情况
    if remindTable[id] == nil
        or remindTable[id][level] == nil then
        return false;
    end

    return true;
end

-- 获取强化项是否已经提醒过
function setStrengthenItemReminded(id, level)
    if remindTable[id] == nil then
        remindTable[id]  = {};
    end

    remindTable[id][level] = 1;
end

-- 判断能否扩建
function canDevelopDetail(id)
    -- 1. 消耗
    local cost = calcCost(id);
    local ret = "";
    for classId, count in pairs(cost) do
        -- 物品
        if type(classId) == "number" then
            if ItemM.getAmount(ME.user, classId) < count then
                if classId == RELIC_SCRAP_ID then
                    return "relic_scrap_lack", count;
                else
                    local itemName = ItemM.query(classId, "name");
                    ret = string.format(getLocStr("fail_to_do_operate"), itemName, getLocStr("tab_title_strengthen"));
                end

                break;
            end
        else
            if ME.user:queryAttrib(classId) < count then
                if classId == "gem" then
                    ret = "not_enough_gem_to_strengthen"
                else
                    if classId == "money" then
                        ret = "money_lack", count;
                    else
                        local name = FieldsM.getFieldName(classId);
                        ret = string.format(getLocStr("fail_to_do_operate"),
                             name, getLocStr("tab_title_strengthen"));
                    end
                end
                break;
            end
        end
    end

    local cond = query(id, "condition") or {};

    -- 如果配置了其他强化项的等级要求，则判断其他强化项是否满足条件
    local functionLevel = cond["function_level"];
    if type(functionLevel) == "table" and #functionLevel == 2 then
        local perId = functionLevel[1];
        local levelLimit = functionLevel[2];

        if levelLimit > getLevel(perId) then
            return string.format(getLocStr("relic_function_level_limit"), query(perId, "name"), tostring(levelLimit));
        end
    end

    -- 如果配置了要求某些冈布奥已觉醒，则遍历一下，判断是否都已觉醒
    local awakeSlime = cond["awake_slime"];
    if type(awakeSlime) == "table" and #awakeSlime > 0 then
        for _, petId in ipairs(awakeSlime) do
            if not AwakeM.isCarved(petId) then
                return string.format(getLocStr("awake_carved_limit2"), PetM.query(petId, "short_name"));
            end
        end
    end

    local rule = rules[query(id, "rule")];
    if rule and rule.canDevelop and rule.limitDevelopDesc then
        if not rule.canDevelop(id) then
            ret = rule.limitDevelopDesc(id);
        end
    end

    return ret;
end

-- 是否是星阶限制了
function checkRankLimit(id)
    local ret = false;
    local rule = rules[query(id, "rule")];
    if rule and rule.canDevelop and rule.limitDevelopDesc then
        if not rule.canDevelop(id) then
            ret = true;
        end
    end
    return ret;
end

-- 判断能否扩建
function canDevelop(id)
    -- 1. 消耗
    local cost = calcCost(id);
    local ok = true;
    for classId, count in pairs(cost) do
        -- 物品
        if type(classId) == "number" then
            ok = ItemM.getAmount(ME.user, classId) >= count;
        else
            ok = ME.user:queryAttrib(classId) >= count;
        end

        if not ok then
            return ok;
        end
    end

    -- 2. 是否满级
    local level = getLevel(id);
    if level >= query(id, "max_level") then
        return false;
    end

    -- 如果是0级且有前提条件
    local cond = query(id, "condition") or {};
    local termId = cond["term"];
    if 0 == level and termId and getLevel(termId) <= 0 then
        return false;
    end

    -- 如果配置了其他强化项的等级要求，则判断其他强化项是否满足条件
    local functionLevel = cond["function_level"];
    if type(functionLevel) == "table" and #functionLevel == 2 then
        local perId = functionLevel[1];
        local levelLimit = functionLevel[2];

        if levelLimit > getLevel(perId) then
            return false;
        end
    end

    -- 如果配置了要求某些冈布奥已觉醒，则遍历一下，判断是否都已觉醒
    local awakeSlime = cond["awake_slime"];
    if type(awakeSlime) == "table" and #awakeSlime > 0 then
        for _, petId in ipairs(awakeSlime) do
            if not AwakeM.isCarved(petId) then
                return false;
            end
        end
    end

    local rule = rules[query(id, "rule")];
    if rule and rule.canDevelop then
        return rule.canDevelop(id);
    end

    return true;
end

-- 获取限制描述
function getLimitDesc(id)
    local rule = rules[query(id, "rule")];
    if rule and rule.limitDevelopDesc and rule.canDevelop then
        if not rule.canDevelop(id) then
            return rule.limitDevelopDesc(id);
        end
    end
    return "";
end

-- 是否满足前提条件
function checkPreCondition(id)
    -- 如果是0级且有前提条件
    local level = getLevel(id);
    local cond = query(id, "condition") or {};
    local termId = cond["term"];
    if 0 == level and termId and getLevel(termId) <= 0 then
        return false;
    end

    -- 如果配置了其他强化项的等级要求，则判断其他强化项是否满足条件
    local functionLevel = cond["function_level"];
    if type(functionLevel) == "table" and #functionLevel == 2 then
        local perId = functionLevel[1];
        local levelLimit = functionLevel[2];

        if levelLimit > getLevel(perId) then
            return false;
        end
    end

    local ruleName = query(id, "rule");

    -- 飞艇只要有芯片就可以显示
    if ruleName == "ariship" and cond["ship_id"] then
        return NewAirShipM.getShipChipNum(cond["ship_id"]) > 0 or NewAirShipM.hasOwnShip(cond["ship_id"]);
    end

    local rule = rules[ruleName];
    if rule and rule.canDevelop then
        return rule.canDevelop(id);
    end

    return true;
end

-- 获取强化描述
function getStrengthenDesc(id)
    -- 子规则里去拼接
    local rule = rules[query(id, "rule")];
    if rule and rule.getDesc then
        return rule.getDesc(query(id, "desc"), id);
    end
    return query(id, "desc");
end

-- 扩建
function develop(id, notNotify)
    if not canDevelop(id) then
        return false;
    end

    -- 先消耗
    local cost = calcCost(id);
    for classId, count in pairs(cost) do
        -- 物品
        if type(classId) == "number" then
            ItemM.costAmount(ME.user, classId, count);
        else
            ME.user:costAttrib(classId, count);
        end
    end

    -- 等级提升
    local funcMap = ME.user.dbase:query("relic_function", {});

    funcMap[id] = (funcMap[id] or 0) + 1;
    ME.user.dbase:set("relic_function", funcMap);

    if not notNotify then
        -- 直接发给服务器
        SyncM.addMessage("CMD_RELIC_DEVELOP", {["id"] = id});
        SyncM.startSync();
    end

    return true;
end

-- 判断是否已经开启对应勋章功能
function isOpenMedalFunction(classId)
    local id = medalTable[classId];

    if getLevel(id) > 0 then
        return true;
    end

    return false;
end

-- 判断服务端是否开启
function isServerSkyMedalOpen()
    local isOpen = ServerStatusM.query(MODULE_SWITCH_SKY_MEDAL) or 0;

    return isOpen == 1;
end

-- 判断下是否开启
function itemIsSkyMedal(classId)
    if medalTable[classId] then
        return true;
    end

    return false;
end